package com.ruoyi.param.controller;

import com.ruoyi.base.service.IRoomService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.iot.IotContext;
import com.ruoyi.iot.WebTasksCallBack;
import com.ruoyi.iot.client.NioClient;
import com.ruoyi.iot.domain.CjqMeter;
import com.ruoyi.iot.domain.MeterCallStatus;
import com.ruoyi.iot.domain.vo.MeterCallStatusVo;
import com.ruoyi.param.domain.TparamTp;
import com.ruoyi.param.service.ITparamTpService;
import com.ruoyi.param.utils.TpTimeUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/param/tp")
@Api(tags = "时段参数")
@Slf4j
public class TparamTpController extends BaseController {

    @Value("${iot.webTimeOut}")
    private long webTimeOut;

    @Autowired
    private IRoomService roomService;

    @Autowired
    private ITparamTpService tParamTpService;

    @Autowired
    private IotContext iotContext;

    /**
     * 查询时段参数列表
     */
    @GetMapping("/list")
    @ApiOperation("查询时段参数列表")
    public TableDataInfo<TparamTp> list(TparamTp tparamTp) {
        startPage();
        List<TparamTp> list = tParamTpService.selectTpList(tparamTp);
        return getDataTable(list);
    }

    /**
     * 批量设置时段参数
     */
    @PreAuthorize("@ss.hasPermi('param:tp:set')")
    @PostMapping("/set")
    @ApiOperation("批量设置时段参数")
    public DeferredResult<AjaxResult> set(@RequestBody List<TparamTp> tparamTpList) {

        List<MeterCallStatus> meterCallStatusList = new CopyOnWriteArrayList<>();
        MeterCallStatusVo meterCallStatusVo = new MeterCallStatusVo().setStatusList(meterCallStatusList);
        final DeferredResult<AjaxResult> deferredResult = new DeferredResult<>(webTimeOut);
        deferredResult.onTimeout(() -> deferredResult.setResult(AjaxResult.success(meterCallStatusVo)));

        List<String> roomIds = tparamTpList.stream().map(TparamTp::getRoomId).collect(Collectors.toList());
        Map<String, List<TparamTp>> tparamTpMapList = tparamTpList.stream().collect(Collectors.groupingBy(TparamTp::getRoomId));

        List<CjqMeter> cjqMeterList = roomService.selectCjqMeterList(roomIds);
        if (cjqMeterList.isEmpty()) {
            deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
        }
        CountDownLatch countDownLatch = new CountDownLatch(roomIds.size());
        for (CjqMeter cjqMeter : cjqMeterList) {

            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(cjqMeter.getRoomId()).setStatus(1);
            meterCallStatusList.add(meterCallStatus);

            TparamTp tparamTp = tparamTpMapList.get(cjqMeter.getRoomId()).get(0);
            if (Objects.equals(tparamTp.getAllots(), 1)) {
                NioClient nioClient = iotContext.getNioClientMap().get(cjqMeter.getCjqNo());
                if (nioClient != null) {
                    if (tparamTp.getRunType() == 1) {
                        String[] time = TpTimeUtil.time(tparamTp);
                        if (!nioClient.writePeriods(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(),
                                Short.parseShort(time[2]), time[0], Short.parseShort(time[3]), time[1], new WebTasksCallBack(cjqMeter.getRoomId()) {
                                    @Override
                                    public void callBack(boolean res) {
                                        meterCallStatus.setStatus(res ? 0 : 1);
                                        countDownLatch.countDown();
                                        if (countDownLatch.getCount() == 0) {
                                            deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
                                        }
                                    }
                                }.setTParamTpService(tParamTpService).setTparamTp(tparamTp))
                        ) {
                            countDownLatch.countDown();
                        }
                    } else {
                        nioClient.writePeriods(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(), new WebTasksCallBack(cjqMeter.getRoomId()) {
                            @Override
                            public void callBack(boolean res) {
                                meterCallStatus.setStatus(res ? 0 : 1);
                                countDownLatch.countDown();
                                if (countDownLatch.getCount() == 0) {
                                    deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
                                }
                            }
                        }.setTParamTpService(tParamTpService).setTparamTp(tparamTp));
                    }
                } else {
                    countDownLatch.countDown();
                }
            } else {
                tParamTpService.updateByRoomIdSelective(tparamTp);
                meterCallStatus.setStatus(0);
                countDownLatch.countDown();
                if (countDownLatch.getCount() == 0) {
                    deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
                }
            }
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
            roomIds.remove(cjqMeter.getRoomId());
        }

        for (String roomId : roomIds) {
            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(roomId).setStatus(1);
            meterCallStatusList.add(meterCallStatus);
            countDownLatch.countDown();
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
        }
        return deferredResult;
    }

    /**
     * 召测时段参数
     */
    @PreAuthorize("@ss.hasPermi('param:tp:call')")
    @GetMapping("/call")
    @ApiOperation("召测时段参数")
    public DeferredResult<AjaxResult> call(@RequestParam("roomIds") List<String> roomIds) {

        List<MeterCallStatus> meterCallStatusList = new CopyOnWriteArrayList<>();
        MeterCallStatusVo meterCallStatusVo = new MeterCallStatusVo().setStatusList(meterCallStatusList);
        final DeferredResult<AjaxResult> deferredResult = new DeferredResult<>(webTimeOut);
        deferredResult.onTimeout(() -> deferredResult.setResult(AjaxResult.success(meterCallStatusVo)));

        List<CjqMeter> cjqMeterList = roomService.selectCjqMeterList(roomIds);
        if (cjqMeterList.isEmpty()) {
            deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
        }
        CountDownLatch countDownLatch = new CountDownLatch(roomIds.size());
        for (CjqMeter cjqMeter : cjqMeterList) {

            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(cjqMeter.getRoomId()).setStatus(1);
            meterCallStatusList.add(meterCallStatus);

            NioClient nioClient = iotContext.getNioClientMap().get(cjqMeter.getCjqNo());
            if (nioClient != null) {
                nioClient.readPeriods(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(), new WebTasksCallBack(cjqMeter.getRoomId()) {
                    @Override
                    public void callBack(boolean res) {
                        meterCallStatus.setStatus(res ? 0 : 1);
                        countDownLatch.countDown();
                        if (countDownLatch.getCount() == 0) {
                            deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
                        }
                    }
                }.setTParamTpService(tParamTpService));
            } else {
                countDownLatch.countDown();
            }
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
            roomIds.remove(cjqMeter.getRoomId());
        }

        for (String roomId : roomIds) {
            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(roomId).setStatus(1);
            meterCallStatusList.add(meterCallStatus);
            countDownLatch.countDown();
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
        }
        return deferredResult;
    }

    /**
     * 删除时段参数
     */
    @PreAuthorize("@ss.hasPermi('param:tp:del')")
    @GetMapping("/del")
    @ApiOperation("删除时段参数")
    public AjaxResult del(@RequestParam("roomIds") List<String> roomIds) {
        tParamTpService.deleteByRoomIds(roomIds);
        return AjaxResult.success();
    }
}
